package pl.edu.pw.MidEmu.UI.Controllers;

import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.XMLDecoder;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;

import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JMenuItem;

import pl.edu.pw.MidEmu.Base.Controllers.BaseController;
import pl.edu.pw.MidEmu.Common.Consts;
import pl.edu.pw.MidEmu.Common.Models.ComponentTypeModel;
import pl.edu.pw.MidEmu.Common.Models.EthernetInterfaceModel;
import pl.edu.pw.MidEmu.Common.Models.ComponentTypeModel.ComponentType;
import pl.edu.pw.MidEmu.Logic.ProcessHandler;
import pl.edu.pw.MidEmu.UI.Components.MidasComponent;
import pl.edu.pw.MidEmu.UI.Views.MainFrameView;

/**
 * Controller for main frame and MidEmu workspace
 * @author Mateusz Starodab
 *
 */
public class MainFrameController extends BaseController<MainFrameView> implements ActionListener, WindowListener
{
	/**
	 * @uml.property name="componentTypes"
	 */
	private List<ComponentTypeModel> componentTypes;
	private List<EthernetInterfaceModel> interfaces;
	private List<MidasComponent> midasComponentFrames;
	private Hashtable<String, Boolean> connections;

	@SuppressWarnings("unchecked")
	public MainFrameController()
	{
		midasComponentFrames = new ArrayList<MidasComponent>();
		componentTypes = new ArrayList<ComponentTypeModel>();
		interfaces = new ArrayList<EthernetInterfaceModel>();
		connections = new Hashtable<String, Boolean>();

		try
		{
			File file = new File(Consts.FilePath_ComponentTypes);
			if (file.exists())
			{
				XMLDecoder decoder = new XMLDecoder(new BufferedInputStream(new FileInputStream(file)));
				componentTypes = (List<ComponentTypeModel>) decoder.readObject();
				decoder.close();
			}
		}
		catch (FileNotFoundException ex)
		{
			ex.printStackTrace();
		}
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource() instanceof JButton)
		{
			JButton button = (JButton) e.getSource();
			if (button.getName().contains("component_"))
			{
				midasComponentFrames.add(getView().createComponent(button.getName().replaceAll("component_", "")));
			}
		}
		else if (e.getSource() instanceof JMenuItem)
		{
			JMenuItem item = (JMenuItem) e.getSource();
			if (item.getName() == Consts.MainFrame_ExitMenu)
			{
				getView().dispose();
			}
			else if (item.getName() == Consts.MainFrame_NetworkMenu)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showNetworkSettingsFrame(point);
			}
			else if (item.getName() == Consts.MainFrame_ConnectivityMenu)
			{
				Point point = MouseInfo.getPointerInfo().getLocation();
				getView().showNetworkConnectivityFrame(point);
			}
			else if (item.getName() == Consts.MainFrame_AboutMenu)
			{

			}
			else if (item.getName() == Consts.MainFrame_AuthorMenu)
			{

			}
		}
	}

	public boolean checkCentralNodeRunning()
	{
		for (MidasComponent component : midasComponentFrames)
		{
			if (component.getController().getMidas() != null && component.getController().getMidas().getIsCentralNode())
				return true;
		}
		return false;
	}

	public boolean checkIfIfaceIsUsed(String ifaceName)
	{
		for (EthernetInterfaceModel iface : interfaces)
		{
			if (iface.getName().equals(ifaceName))
				return true;
		}
		return false;
	}

	public void freeIfaceByName(String interfaceName)
	{
		for (EthernetInterfaceModel iface : interfaces)
		{
			if (iface.getName().equals(interfaceName))
				iface.setFree(true);
		}
	}

	public Dimension getButtonMaxDimmension()
	{
		int maxWidth = 0;
		int maxHeight = 0;

		for (int i = 0; i < componentTypes.size(); i++)
		{
			Icon icon = componentTypes.get(i).getIcon();
			if (icon.getIconWidth() > maxWidth)
				maxWidth = icon.getIconWidth();
			if (icon.getIconHeight() > maxHeight)
				maxHeight = icon.getIconHeight();
		}

		return new Dimension(maxWidth + 36, maxHeight + 10);
	}

	public String getCentralNodeIP()
	{
		for (MidasComponent component : midasComponentFrames)
		{
			if (component.getController().getMidas() != null && component.getController().getMidas().getIsCentralNode())
				return component.getController().getMidas().getIpAddress();
		}
		return "";
	}

	public MidasComponent getCentralNodeModel()
	{
		for (MidasComponent component : midasComponentFrames)
		{
			if (component.getController().getMidas() != null && component.getController().getMidas().getIsCentralNode())
				return component;
		}
		return null;
	}

	public ComponentTypeModel getComponentType(int index)
	{
		return componentTypes.get(index);
	}

	/**
	 * @return
	 * @uml.property name="componentTypes"
	 */
	public List<ComponentTypeModel> getComponentTypes()
	{
		return componentTypes;
	}

	public int getFirstFreeIndexForComponents(ComponentType componentType)
	{
		int firstFree = 1;
		boolean hasNumber = false;
		while (true)
		{
			ListIterator<MidasComponent> listIterator = midasComponentFrames.listIterator();
			while (listIterator.hasNext())
			{
				MidasComponent ctm = listIterator.next();
				if (ctm.getComponentType().getComponentType() == componentType)
				{
					int breakIndex = ctm.getName().indexOf(" ");
					String number = ctm.getName().substring(breakIndex + 1);
					int currentNumber = Integer.parseInt(number);
					if (currentNumber == firstFree)
					{
						hasNumber = true;
						break;
					}
				}
			}
			if (!hasNumber)
				return firstFree;
			hasNumber = false;
			firstFree++;
		}
	}

	public List<EthernetInterfaceModel> getFreeInterfaces()
	{
		List<EthernetInterfaceModel> freeInterfaces = new ArrayList<EthernetInterfaceModel>();
		for (EthernetInterfaceModel iface : interfaces)
		{
			if (iface.isFree())
			{
				freeInterfaces.add(iface);
			}
		}
		return freeInterfaces;
	}

	public void registerIface(EthernetInterfaceModel model)
	{
		if (!checkIfIfaceIsUsed(model.getName()))
			interfaces.add(model);
	}

	public void removeMidasComponent(MidasComponent midasComponent)
	{
		midasComponentFrames.remove(midasComponent);
		midasComponent.terminate();
	}

	public void unregisterIface(String name)
	{
		for (int i = 0; i < interfaces.size(); i++)
		{
			if (interfaces.get(i).getName().equals(name))
			{
				interfaces.remove(i);
				break;
			}
		}
	}

	@Override
	public void windowActivated(WindowEvent e)
	{
	}

	@Override
	public void windowClosed(WindowEvent e)
	{
	}

	@Override
	public void windowClosing(WindowEvent e)
	{
		for (MidasComponent item : midasComponentFrames)
		{
			item.terminate();
		}

		ProcessHandler h = new ProcessHandler("./data/cleanup", "", "");
		h.start();
	}

	@Override
	public void windowDeactivated(WindowEvent e)
	{
	}

	@Override
	public void windowDeiconified(WindowEvent e)
	{
	}

	@Override
	public void windowIconified(WindowEvent e)
	{
	}

	@Override
	public void windowOpened(WindowEvent e)
	{
	}

	public List<EthernetInterfaceModel> getRegisteredInterfaces()
	{
		return interfaces;
	}

	public boolean checkIfEnabled(String a, String b)
	{
		for (String key : connections.keySet())
		{
			if (key.equals(a + "_" + b))
				return connections.get(key);
		}
		return true;
	}

	public void setConnection(String name, boolean b)
	{
		if (connections.containsKey(name))
			connections.remove(name);

		connections.put(name, b);
	}

	public Hashtable<String, String> getNodesIDsAndIPs()
	{
		Hashtable<String, String> temp = new Hashtable<String, String>();

		for (MidasComponent midas : midasComponentFrames)
		{
			temp.put(midas.getController().getMidas().getNodeName(), midas.getController().getMidas().getIpAddress());
		}

		return temp;
	}

	public Hashtable<String, String> getNodesInterfacesAndIPS()
	{
		Hashtable<String, String> temp = new Hashtable<String, String>();

		for (EthernetInterfaceModel ethInterface : interfaces)
		{
			temp.put(ethInterface.getDisplayName(), ethInterface.getIpAddress());
		}

		return temp;
	}
}
